package cn.merge;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import lombok.extern.slf4j.Slf4j;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.ss.util.CellRangeAddress;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;

/**
 * @author summit
 * @since 2022/4/27 13:39
 */
@Slf4j
public class ExcelCellMergeTest {

	/**
	 * @param title 标题集合 tilte的长度应该与list中的model的属性个数一致
	 * @param maps 内容集合
	 * @param mergeIndex 合并单元格的列
	 */
	public static String createExcel(String[] title, Map<String, List<List<String>>> maps, List<Integer> mergeIndex) {
		if (title.length == 0) {
			return null;
		}
		/*初始化excel模板*/
		Workbook workbook = new XSSFWorkbook();
		Sheet sheet = null;
		int n = 0;
		/*循环sheet页*/
		for (Map.Entry<String, List<List<String>>> entry : maps.entrySet()) {
			/*实例化sheet对象并且设置sheet名称，book对象*/
			sheet = workbook.createSheet();

			workbook.setSheetName(n, entry.getKey());
			workbook.setSelectedTab(0);

			for (int i = 0; i < title.length; i++) {
				sheet.autoSizeColumn(i, true);
				sheet.setColumnWidth(i, sheet.getColumnWidth(i) * 2);
			}
			/*初始化head，填值标题行（第一行）*/
			Row row0 = sheet.createRow(0);
			for (int i = 0; i < title.length; i++) {
				Cell cell1 = row0.createCell(i);
				cell1.setCellValue(title[i]);
			}

			/*得到当前sheet下的数据集合*/
			List<List<String>> list = entry.getValue();
			/*遍历该数据集合*/
			List<PoiModel> poiModels = new ArrayList<>();
			Iterator<List<String>> iterator = list.iterator();
			/*这里1是从excel的第二行开始，第一行已经塞入标题了*/
			int index = 1;
			while (iterator.hasNext()) {
				Row row = sheet.createRow(index);
				/*取得当前这行的map，该map中以key，value的形式存着这一行值*/
				List<String> dataList = iterator.next();
				/*循环列数，给当前行塞值*/
				for (int i = 0; i < title.length; i++) {
					/*循环需要合并的列*/
					if (index == 1) {
						/*记录第一行的开始行和开始列*/
						PoiModel poiModel = new PoiModel();
						poiModel.setOldContent(dataList.get(i));
						poiModel.setContent(dataList.get(i));
						poiModel.setRowIndex(1);
						poiModel.setCellIndex(i);
						poiModels.add(poiModel);
					} else if (mergeIndex.contains(i)) {
						if (poiModels.get(i).getContent().equals(dataList.get(i))) {
							/*重新记录该列的内容为当前内容，行标记改为当前行标记，列标记则为当前列*/
							poiModels.get(i).setContent(dataList.get(i));
							poiModels.get(i).setCellIndex(i);
						} else {
							/*当前行的当前列与上一行的当前列的内容不一致时，则把当前行以上的合并*/
							if (poiModels.get(i).getRowIndex() != index - 1) {
								CellRangeAddress cra = new CellRangeAddress(poiModels.get(i).getRowIndex(), index - 1, i, i);
								//在sheet里增加合并单元格
								sheet.addMergedRegion(cra);
								poiModels.get(i).setContent(dataList.get(i));
							}
							poiModels.get(i).setRowIndex(index);
						}
					}

					if (index == list.size() && mergeIndex.contains(i)) {
						if (poiModels.get(i).getRowIndex() != index) {
							CellRangeAddress cra = new CellRangeAddress(poiModels.get(i).getRowIndex(), index, i, i);
							//在sheet里增加合并单元格
							sheet.addMergedRegion(cra);
						}
					}

					Cell cell = row.createCell(i);
					cell.setCellValue(dataList.get(i));
				}


				index++;
			}
			n++;
		}
		/*生成临时文件*/
		FileOutputStream out = null;
		String localPath = null;
		File tempFile = null;
		String fileName = String.valueOf(System.currentTimeMillis() / 1000);
		try {
			String path = "C:\\java-kaifa\\tongyu-workspace\\me\\springboot-jar\\excel\\src\\main\\resources\\";
//			tempFile = File.createTempFile(fileName, ".xlsx");
//			localPath = tempFile.getAbsolutePath();
			out = new FileOutputStream(path + fileName + ".xlsx");
			workbook.write(out);
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			try {
				out.flush();
				out.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		return localPath;
	}

	public static void main(String[] args) throws IOException {
		/*此处标题的数组则对应excel的标题*/
		String[] title = { "id", "标题", "描述", "负责人", "开始时间1111111111111111111111111111111111111111111" };
		List<Map<String, String>> list = new ArrayList<>();
		/*这边是制造一些数据，注意每个list中map的key要和标题数组中的元素一致*/
		for (int i = 0; i < 10; i++) {
			HashMap<String, String> map = new HashMap();
			if (i > 5) {
				if (i < 7) {
					map.put("id", "333");
					map.put("标题", "mmmm");
				} else {
					map.put("id", "333");
					map.put("标题", "aaaaa");
				}
			} else if (i > 3) {
				map.put("id", "222");
				map.put("标题", "哈哈哈哈");
			} else if (i > 1 && i < 3) {
				map.put("id", "222");
				map.put("标题", "hhhhhhhh");
			} else {
				map.put("id", "222");
				map.put("标题", "bbbb");
			}
			map.put("描述", "sssssss");
			map.put("负责人", "vvvvv");
			map.put("开始时间", "2017-02-27 11:20:26");
			list.add(map);
		}
		Map<String/*此处的key为每个sheet的名称，一个excel中可能有多个sheet页*/, List<Map<String/*此处key对应每一列的标题*/, String>>/*该list为每个sheet页的数据*/> map = new HashMap<>();
		map.put("测试合并数据", list);

		Map<String, List<List<String>>> map1 = new HashMap<>();
		List<List<String>> listData = new ArrayList<>();
		map1.put("ssssssss", listData);
		List<String> strList = new ArrayList<>();
		strList.add("1");
		strList.add("2222");
		strList.add("bbb");
		strList.add("cccccc");
		strList.add("dddddddddddddddddddddddddddddddddddddddddddddd");

		listData.add(strList);

		List<String> strList2 = new ArrayList<>();
		strList2.add("2");
		strList2.add("2222");
		strList2.add("bbbb");
		strList2.add("cccccc");
		strList2.add("ddddddddd");

		List<String> strList3 = new ArrayList<>();
		strList3.add("3");
		strList3.add("222");
		strList3.add("bbb");
		strList3.add("ccccc");
		strList3.add("ddddddddd");


		List<String> strList4 = new ArrayList<>();
		strList4.add("4");
		strList4.add("22");
		strList4.add("bbb");
		strList4.add("cccc");
		strList4.add("ddddddddd");

		listData.add(strList2);
		listData.add(strList3);
		listData.add(strList4);


		System.out.println(createExcel(title, map1, Arrays.asList(0, 1, 2, 3)/*此处数组为需要合并的列，可能有的需求是只需要某些列里面相同内容合并*/));
	}
}
